/**
 * 
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 * 
 *   http://www.apache.org/licenses/LICENSE-2.0
 *   
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 * 
 */
package org.jiopi.ibean.kernel;

import java.io.InputStream;
import java.lang.instrument.Instrumentation;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.HashMap;
import org.apache.log4j.Logger;
import org.jiopi.framework.ModuleConsole;
import org.jiopi.framework.core.CentralConsoleKernel;
import org.jiopi.framework.core.JiopiConfigConstants;
import org.jiopi.ibean.kernel.context.ContextCentralConsoleKernel;
import org.jiopi.ibean.kernel.context.ModuleConsoleImpl;
import org.jiopi.ibean.kernel.remote.RemoteModuleConsoleImpl;
import org.jiopi.ibean.kernel.util.ConfigUtil;
import org.jiopi.ibean.kernel.util.ObjectAccessor;
import org.jiopi.ibean.kernel.util.XMLMerger;
import org.jiopi.remote.RemoteCentralConsole;
import org.dom4j.io.SAXReader;

/**
 * 
 * kernel share的 CentralConsoleKernel
 * 负责维护 不同 Context 下 kernel 的 实例
 * 
 * 
 * 每个iBeanContext使用独立的一个kernel目录,使用ContextClassLoader中jiopi配置的work_dir
 * 创建唯一 context 目录
 * context/modules/module_name_version 目录 为每个module的工作目录
 * context/tmp/classloader{ID}下存放classloader的临时文件
 * 
 * 
 * 
 * 维护统一资源库
 * 
 * @since 2010.4.17
 *
 */
public class IBeanCentralConsoleKernel implements CentralConsoleKernel {
	
	private static Logger logger = Logger.getLogger( IBeanCentralConsoleKernel.class );
	
	private final static HashMap<ClassLoader,ContextCentralConsoleKernel> contextKernels = new HashMap<ClassLoader,ContextCentralConsoleKernel>();
	
	private HashMap<NameVersion,ModuleConsole> accessModuleConsoleMap = new HashMap<NameVersion,ModuleConsole>();
	
	private static Instrumentation INS = null;
	
	/**
	 * 获得上下文的 CentralConsoleKernel
	 * @return
	 */
	private ContextCentralConsoleKernel getContextCentralConsoleKernel(){
		
		ContextCentralConsoleKernel ccck = null;
		
		ClassLoader iBeanContextClassLoader = ConfigUtil.getIBeanContextClassLoader();
		synchronized(contextKernels){
			ccck = contextKernels.get(iBeanContextClassLoader);
		}
		if(ccck==null){//暂时不存在
			synchronized(iBeanContextClassLoader){
				synchronized(contextKernels){
					ccck = contextKernels.get(iBeanContextClassLoader);
				}
				if(ccck == null){
					ccck = new ContextCentralConsoleKernel(iBeanContextClassLoader);//初始化
					synchronized(contextKernels){
						contextKernels.put(iBeanContextClassLoader, ccck);
					}
				}
			}
		}
		return ccck;
	}
	
	public static Instrumentation getInstrumentation(){
		return INS;
	}
	
	public ModuleConsole accessModuleConsole(String moduleName,String compatibleVersion) {
		if(moduleName.startsWith("remote://")){//a remote ModuleConsole
			NameVersion needNameVersion = new NameVersion(moduleName,compatibleVersion);
			ModuleConsole rmc = null;
			synchronized(accessModuleConsoleMap){
				rmc = accessModuleConsoleMap.get(needNameVersion);
			}
			if(rmc == null){
				synchronized(needNameVersion.toString().intern()){
					synchronized(accessModuleConsoleMap){
						rmc = accessModuleConsoleMap.get(needNameVersion);
					}
					if(rmc == null){
						try {
							URI moduleURI = new URI(moduleName);
							String remoteModule = moduleURI.getUserInfo();
							String host = moduleURI.getHost();
							String realModuleName = moduleURI.getPath().substring(1);
							//System.out.println("moduleName:"+moduleName);
							//System.out.println("remoteModule:"+remoteModule);
							//System.out.println("host:"+host);
							//System.out.println("realModuleName:"+realModuleName);
							RemoteCentralConsole rcc = accessModuleConsole(remoteModule, "0.5").accessControlPanel("jiopi.RemoteCentralConsole?"+host, RemoteCentralConsole.class);
							ModuleConsole getRmc = new RemoteModuleConsoleImpl(rcc,realModuleName,compatibleVersion);
							synchronized(accessModuleConsoleMap){
								rmc = accessModuleConsoleMap.get(needNameVersion);
								if(rmc == null){
									rmc = getRmc;
									accessModuleConsoleMap.put(needNameVersion, rmc);
								}
							}
						} catch (URISyntaxException e) {
							throw new RuntimeException(e);
						}
					}
				}
			}
			
			return rmc;
		}else{
			ClassLoader ocl = ModuleConsoleImpl.originContextClassLoader.get();
			ClassLoader contextClassLoader = null;
			try{
				if(ocl!=null){
					contextClassLoader = Thread.currentThread().getContextClassLoader();
					Thread.currentThread().setContextClassLoader(ocl);
				}
				return getContextCentralConsoleKernel().accessModuleConsole(moduleName, compatibleVersion);
			}finally{
				if(contextClassLoader!=null)Thread.currentThread().setContextClassLoader( contextClassLoader );
			}
		}
	}
	
	public ClassLoader getClassLoader() {
		return getContextCentralConsoleKernel().getClassLoader();
	}

	public <T> T objectOperate(Object obj, String registerName, Class<T> returnType,Object... args) {
		return ObjectAccessor.method(obj, registerName, returnType, args);
	}
	
	public <T> T objectOperateStrict(Object obj, String registerName,Class<T> returnType, Object[] parameterTypes, Object... args) {
		return ObjectAccessor.strictMethod(obj, registerName, returnType, parameterTypes, args);
	}

	public <T> T objectVariable(Object obj, String variableName, Class<T> returnType) {
		return ObjectAccessor.variable(obj, variableName, returnType);
	}

	public void refreshResource(String modulename, String version) {
		// TODO Auto-generated method stub

	}

	public void restart() {}
	public void setRootClassLoader(ClassLoader classLoader) {}
	public void shutdown() {}
	public void start() {}
	
	/**
	 * 初始化函数
	 * @param ins //传递Instrumentation以便完成HotSwap
	 */
	public void init(Instrumentation ins){
		logger.info(KernelConstants.COPY_RIGHT);
		if(INS==null) INS = ins;
		//read a test XML file for kernel XML parser initialization
		new SAXReader().getDocumentFactory();
		URL jiopiConfig = Thread.currentThread().getContextClassLoader().getResource(JiopiConfigConstants.ASSEMBLING_FILE);
		if(jiopiConfig!=null){
			try{
				InputStream is = jiopiConfig.openStream();
				XMLMerger.readDocumentAndCloseStream(is);
				logger.info(" XML parser initialized");
			}catch(Exception e){
				logger.warn("initialization XML parser error",e);
			}
		}
	}
	
	public void init(){
		getContextCentralConsoleKernel();
	}

}
